bounce1d.c

/*
 * bounceld.c
 * pupose       animation with user controlled speed and direction
 * note         the handler does the animation
 *              the main program reads keyboard input
 * compile      cc bounceld.c set_ticker.c -lcurses -o bounceld
 */
#include <stdio.h>
#include <curses.h>
#include <signal.h>

#define MESSAGE "hello"
#define BLANK   "     "

int row;     /* current row */
int col;     /* current column */
int dir;     /* where we are going */

int main()
{
    int delay;     /* bigger => slower */
    int ndelay;    /* new delay */
    int c;         /* user input */
    void move_msg(int); /* handler for timer */

    initscr();
    crmode();
    noecho();
    clear();

    row = 10;
    col = 0;
    dir = 1;
    delay = 200;

    move (row, col);
    addstr(MESSAGE);
    signal(SIGALRM, move_msg);
    set_ticker(delay);
    while (1){
        ndelay = 0;
        c = getch();
        if (c == 'Q') break;
        if (c == ' ') dir = -dir;
        if (c == 'f' && delay > 2) ndelay = delay / 2;
        if (c == 's') ndelay = delay * 2;
        if (ndelay > 0)
            set_ticker(delay = ndelay);
    }
    endwin();
    return 0;
}

void move_msg(int signum)
{
    signal(SIGALRM, move_msg);  /* reset, just in case */
    move(row, col);
    addstr(BLANK);
    col += dir;
    move(row, col);
    addstr(MESSAGE);
    refresh();
    if (dir == -1 && col <= 0)
        dir = 1;
    else if (dir == 1 && col + strlen(MESSAGE) >= COLS)
        dir = -1;
}

bounce2d.c

/*
 * bounce2d 1.0
 * bounce a character (default is 'o') around the screen
 *  defined by some parameters
 * user input: s slow down x component, S: slow y component
 *             f speed up x component, F: speed y component
 *             Q quit
 * blocks on read, but timer tick sends SIGALRM caught by ball_move
 * build: cc bounce2d.c set_ticker.c -lcurses -o bounce2d
 */
#include <curses.h>
#include <signal.h>
#include "bounce.h"

struct ppball the_ball;

/** the main loop **/
void set_up();
void wrap_up();
int bounce_or_lose(struct ppball *);

int main()
{
    int c;
    set_up();
    while (((c = getchar())) != 'Q')
    {
        if (c == 'f') the_ball.x_ttm--;
        else if (c == 's') the_ball.x_ttm++;
        else if (c == 'F') the_ball.y_ttm--;
        else if (c == 'S') the_ball.y_ttm++;
    }
    wrap_up();
    return 0;
}

void set_up()
    /*
     * init structure and other stuff
     */
{
    void ball_move(int);
    the_ball.y_pos = Y_INIT;
    the_ball.x_pos = X_INIT;
    the_ball.y_ttg = the_ball.y_ttm = Y_TIM;
    the_ball.x_ttg = the_ball.x_ttm = X_TIM;
    the_ball.y_dir = 1;
    the_ball.x_dir = 1;
    the_ball.symbol = DFL_SYMBOL;

    initscr();
    noecho();
    crmode();

    signal(SIGINT, SIG_IGN);
    mvaddch(the_ball.y_pos, the_ball.x_pos, the_ball.symbol);
    refresh();
    signal(SIGALRM, ball_move);
    set_ticker(1000 / TICKS_PER_SEC);
}

void wrap_up()
{
    set_ticker(0);
    endwin();
}

void ball_move(int signum)
{
    int y_cur, x_cur, moved;

    signal(SIGALRM, SIG_IGN);
    x_cur = the_ball.x_pos;
    y_cur = the_ball.y_pos;
    moved = 0;

    if (the_ball.y_ttm > 0 &&  the_ball.y_ttg-- == 1){
        the_ball.y_pos += the_ball.y_dir;  /* move */
        the_ball.y_ttg = the_ball.y_ttm;   /* reset */
        moved = 1;
    }

    if (the_ball.x_ttm > 0 && the_ball.x_ttg-- == 1){
        the_ball.x_pos += the_ball.x_dir;  /* move */
        the_ball.x_ttg = the_ball.x_ttm;   /* reset */
        moved = 1;
    }

    if (moved){
        mvaddch(y_cur, x_cur, BLANK);
        mvaddch(y_cur, x_cur, BLANK);
        mvaddch(the_ball.y_pos, the_ball.x_pos, the_ball.symbol);
        bounce_or_lose(&the_ball);
        move(LINES-1, COLS-1);
        refresh();
    }
    signal(SIGALRM, ball_move);
}

int bounce_or_lose(struct ppball *bp)
{
    int return_val = 0;

    if (bp->y_pos == TOP_ROW){
        bp->y_dir = 1;
        return_val = 1;
    }else if (bp->y_pos == BOT_ROW){
        bp->y_dir = -1;
        return_val = 1;
    }

    if (bp->x_pos == LEFT_EDGE){
        bp->x_dir = 1;
        return_val = 1;
    }else if (bp->x_pos == RIGHT_EDGE){
        bp->x_dir = -1;
        return_val = 1;
    }
    return return_val;
}

bounce.h

#define BLANK ' '
#define DFL_SYMBOL 'o'
#define TOP_ROW 5
#define BOT_ROW 20
#define LEFT_EDGE 10
#define RIGHT_EDGE 70
#define X_INIT 10
#define Y_INIT 10
#define TICKS_PER_SEC 50
#define Y_TIM 8
#define X_TIM 8

struct ppball {
    int x_ttg; // x 轴下次重画还要等待多少个计时器
    int y_ttg; // y 轴下次重画还要等待多少个计时器
    int x_ttm; // x 轴移动需要等待的信号间隔
    int y_ttm; // y 轴移动需要等待的信号间隔
    int y_pos;
    int x_pos;
    int y_dir;
    int x_dir;
    char symbol;
};

bug:

bounce2d. 在移动时, x_ttm 和 y_ttm 值不一样会导致移动先移动 x/y 轴, 刷新 然后再移动另外一个轴, 给人的感觉很傻, 可以判断是否两个轴都改动了, 然后再 刷新

bounce2d1.c

/*
 * bounce2d 1.0
 * bounce a character (default is 'o') around the screen
 *  defined by some parameters
 * user input: s slow down x component, S: slow y component
 *             f speed up x component, F: speed y component
 *             Q quit
 * blocks on read, but timer tick sends SIGALRM caught by ball_move
 * build: cc bounce2d.c set_ticker.c -lcurses -o bounce2d
 */
#include <curses.h>
#include <signal.h>
#include "bounce.h"

struct ppball the_ball;

/** the main loop **/
void set_up();
void wrap_up();
int bounce_or_lose(struct ppball *);

int main()
{
    int c;
    set_up();
    while (((c = getchar())) != 'Q')
    {
        if (c == 'f') the_ball.x_ttm--;
        else if (c == 's') the_ball.x_ttm++;
        else if (c == 'F') the_ball.y_ttm--;
        else if (c == 'S') the_ball.y_ttm++;
    }
    wrap_up();
    return 0;
}

void set_up()
    /*
     * init structure and other stuff
     */
{
    void ball_move(int);
    the_ball.y_pos = Y_INIT;
    the_ball.x_pos = X_INIT;
    the_ball.y_ttg = the_ball.y_ttm = Y_TIM;
    the_ball.x_ttg = the_ball.x_ttm = X_TIM;
    the_ball.y_dir = 1;
    the_ball.x_dir = 1;
    the_ball.symbol = DFL_SYMBOL;
    the_ball.x_moved = the_ball.y_moved = false;

    initscr();
    noecho();
    crmode();

    signal(SIGINT, SIG_IGN);
    mvaddch(the_ball.y_pos, the_ball.x_pos, the_ball.symbol);
    refresh();
    signal(SIGALRM, ball_move);
    set_ticker(1000 / TICKS_PER_SEC);
}

void wrap_up()
{
    set_ticker(0);
    endwin();
}

void ball_move(int signum)
{
    int y_cur, x_cur, moved;

    signal(SIGALRM, SIG_IGN);
    x_cur = the_ball.x_pos;
    y_cur = the_ball.y_pos;
    moved = 0;

    if (the_ball.y_ttm > 0 &&  the_ball.y_ttg-- == 1){
        the_ball.y_pos += the_ball.y_dir;  /* move */
        the_ball.y_ttg = the_ball.y_ttm;   /* reset */
        the_ball.y_moved = 1;
        moved = 1;
    }

    if (the_ball.x_ttm > 0 && the_ball.x_ttg-- == 1){
        the_ball.x_pos += the_ball.x_dir;  /* move */
        the_ball.x_ttg = the_ball.x_ttm;   /* reset */
        the_ball.x_moved = 1;
        moved = 1;
    }

    if (moved){
        mvaddch(y_cur, x_cur, BLANK);
        mvaddch(y_cur, x_cur, BLANK);
        mvaddch(the_ball.y_pos, the_ball.x_pos, the_ball.symbol);
        bounce_or_lose(&the_ball);
        move(LINES-1, COLS-1);
        if (the_ball.x_moved && the_ball.y_moved){
            refresh();
            the_ball.x_moved = the_ball.y_moved = false; /* reset */
        }
    }
    signal(SIGALRM, ball_move);
}

int bounce_or_lose(struct ppball *bp)
{
    int return_val = 0;

    if (bp->y_pos == TOP_ROW){
        bp->y_dir = 1;
        return_val = 1;
    }else if (bp->y_pos == BOT_ROW){
        bp->y_dir = -1;
        return_val = 1;
    }

    if (bp->x_pos == LEFT_EDGE){
        bp->x_dir = 1;
        return_val = 1;
    }else if (bp->x_pos == RIGHT_EDGE){
        bp->x_dir = -1;
        return_val = 1;
    }
    return return_val;
}

bounce.h

#define BLANK ' '
#define DFL_SYMBOL 'o'
#define TOP_ROW 5
#define BOT_ROW 20
#define LEFT_EDGE 10
#define RIGHT_EDGE 70
#define X_INIT 10
#define Y_INIT 10
#define TICKS_PER_SEC 50
#define Y_TIM 8
#define X_TIM 8

struct ppball {
    int x_ttg; // x 轴下次重画还要等待多少个计时器
    int y_ttg; // y 轴下次重画还要等待多少个计时器
    int x_ttm; // x 轴移动需要等待的信号间隔
    int y_ttm; // y 轴移动絮叨等待的信号间隔
    int y_pos;
    int x_pos;
    int y_dir;
    int x_dir;
    int x_moved;
    int y_moved;
    char symbol;
};

继续实现, 添加挡板 bounce2d2.c

/*
 * bounce2d 1.0
 * bounce a character (default is 'o') around the screen
 *  defined by some parameters
 * user input: s slow down x component, S: slow y component
 *             f speed up x component, F: speed y component
 *             Q quit
 * blocks on read, but timer tick sends SIGALRM caught by ball_move
 * build: cc bounce2d.c set_ticker.c -lcurses -o bounce2d
 */
#include <curses.h>
#include <string.h>
#include <signal.h>
#include "bounce.h"

struct ppball the_ball;

/** the main loop **/
int flap_pos = RIGHT_EDGE / 2 - LEFT_EDGE;
int old_pos;
void set_up();
void wrap_up();
void move_flap();
int bounce_or_lose(struct ppball *);

int main()
{
    int c;
    set_up();
    while (((c = getchar())) != 'Q')
    {
        if (c == 'f') the_ball.x_ttm--;
        else if (c == 's') the_ball.x_ttm++;
        else if (c == 'F') the_ball.y_ttm--;
        else if (c == 'S') the_ball.y_ttm++;
        else if (c == 'a'){
            if (flap_pos > LEFT_EDGE){
                old_pos = flap_pos;
                flap_pos -= FLAP_SEEPD;
                move_flap();
            }
        }else if (c == 'd'){
            if (flap_pos < RIGHT_EDGE){
                old_pos = flap_pos;
                flap_pos += FLAP_SEEPD;
                move_flap();
            }
        }
    }
    wrap_up();
    return 0;
}

void set_up()
    /*
     * init structure and other stuff
     */
{
    void ball_move(int);
    the_ball.y_pos = Y_INIT;
    the_ball.x_pos = X_INIT;
    the_ball.y_ttg = the_ball.y_ttm = Y_TIM;
    the_ball.x_ttg = the_ball.x_ttm = X_TIM;
    the_ball.y_dir = 1;
    the_ball.x_dir = 1;
    the_ball.symbol = DFL_SYMBOL;
    the_ball.x_moved = the_ball.y_moved = false;

    initscr();
    noecho();
    crmode();

    signal(SIGINT, SIG_IGN);
    mvaddch(the_ball.y_pos, the_ball.x_pos, the_ball.symbol);
    move_flap();
    signal(SIGALRM, ball_move);
    set_ticker(1000 / TICKS_PER_SEC);
}

void wrap_up()
{
    set_ticker(0);
    endwin();
}

void move_flap()
{
    move(BOT_ROW+1, old_pos);
    addstr(FLAP);
    move(BOT_ROW+1, flap_pos);
    standout();
    addstr(FLAP);
    standend();
    refresh();
}

void ball_move(int signum)
{
    int y_cur, x_cur, moved;

    signal(SIGALRM, SIG_IGN);
    x_cur = the_ball.x_pos;
    y_cur = the_ball.y_pos;
    moved = 0;

    if (the_ball.y_ttm > 0 &&  the_ball.y_ttg-- == 1){
        the_ball.y_pos += the_ball.y_dir;  /* move */
        the_ball.y_ttg = the_ball.y_ttm;   /* reset */
        the_ball.y_moved = 1;
        moved = 1;
    }

    if (the_ball.x_ttm > 0 && the_ball.x_ttg-- == 1){
        the_ball.x_pos += the_ball.x_dir;  /* move */
        the_ball.x_ttg = the_ball.x_ttm;   /* reset */
        the_ball.x_moved = 1;
        moved = 1;
    }

    if (moved){
        mvaddch(y_cur, x_cur, BLANK);
        mvaddch(y_cur, x_cur, BLANK);
        mvaddch(the_ball.y_pos, the_ball.x_pos, the_ball.symbol);
        if(bounce_or_lose(&the_ball)){
            signal(SIGALRM, SIG_IGN);
            move(LINES / 2, COLS / 2);
            addstr("GAME OVER");
            refresh();
            return;
        }
        move(LINES-1, COLS-1);
        if (the_ball.x_moved && the_ball.y_moved){
            refresh();
            the_ball.x_moved = the_ball.y_moved = false; /* reset */
        }
    }
    signal(SIGALRM, ball_move);
}

int bounce_or_lose(struct ppball *bp)
    /*
     * 1 lose
     * 0 not lose
     */
{
    int return_val = 0;

    if (bp->y_pos == TOP_ROW){
        bp->y_dir = 1;
    }else if (bp->y_pos == BOT_ROW){
        bp->y_dir = -1;
        if (!(bp->x_pos >= flap_pos && bp->x_pos <= (flap_pos + (int)strlen(FLAP)))){
            return_val = 1;
        }
    }

    if (bp->x_pos == LEFT_EDGE){
        bp->x_dir = 1;
    }else if (bp->x_pos == RIGHT_EDGE){
        bp->x_dir = -1;
    }
    return return_val;
}

bounce.h

#define BLANK ' '
#define DFL_SYMBOL 'o'
#define TOP_ROW 5
#define BOT_ROW 20
#define LEFT_EDGE 10
#define RIGHT_EDGE 70
#define X_INIT 10
#define Y_INIT 10
#define TICKS_PER_SEC 50
#define Y_TIM 8
#define X_TIM 8
#define FLAP "      "

struct ppball {
    int x_ttg; // x 轴下次重画还要等待多少个计时器
    int y_ttg; // y 轴下次重画还要等待多少个计时器
    int x_ttm; // x 轴移动需要等待的信号间隔
    int y_ttm; // y 轴移动絮叨等待的信号间隔
    int y_pos;
    int x_pos;
    int y_dir;
    int x_dir;
    int x_moved;
    int y_moved;
    char symbol;
};